package cn.mesmile.excel.config;

import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.parsers.DynamicTableNameParser;
import com.baomidou.mybatisplus.extension.parsers.ITableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author zb
 * @date 2020/3/9 22:57
 * @Description:
 */
//@EnableTransactionManagement
@Slf4j
@Configuration
public class MybatisPlusConfig {

    public static ThreadLocal<String> myTableName = new ThreadLocal<>();

    /**
     *  序列化枚举保存到数据库
     * @return
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer(){
        return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    }

    /**
     * 自定义ID 生成器
     * @return
     */
//    @Bean
//    public IdentifierGenerator identifierGenerator() {
//        return new CustomIdGenerator();
//    }

    /**
     *  mybatis-plus 的配置  分页配置
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();

        ArrayList<ISqlParser> sqlParsers = new ArrayList<>();

        // 动态表名解析器
        DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();

        HashMap<String, ITableNameHandler> tableNameHandlerHashMap = new HashMap<>();

        tableNameHandlerHashMap.put("employees", new ITableNameHandler() {
            @Override
            public String dynamicTableName(MetaObject metaObject, String sql, String tableName) {

                log.info("metaObject:  {}", metaObject);
                log.info("原表执行的 sql:  {}", sql);
                log.info("原表的名称 tableName:  {}", tableName);

                // 如果返回的值为空，则不进行替换  这里返回的事 动态表名
                return myTableName.get();
            }

        });

        dynamicTableNameParser.setTableNameHandlerMap(tableNameHandlerHashMap);

        sqlParsers.add(dynamicTableNameParser);
        paginationInterceptor.setSqlParserList(sqlParsers);


        /**
        // 租户解析器
        TenantSqlParser tenantSqlParser = new TenantSqlParser();
        tenantSqlParser.setTenantHandler(new TenantHandler() {
            @Override
            public Expression getTenantId(boolean where) {
                // 租户的id
                return new LongValue(1088248166370832385L);
            }
            // 多租户字段是什么
            @Override
            public String getTenantIdColumn() {
                // 这是表中的字段名,即 用于区分租户的字段
                return "manager_id";
            }

            // 是否需要排除某些表，不加租户字段
            @Override
            public boolean doTableFilter(String tableName) {
                // 为 角色 表的时候，不增加租户信息
                if("role".equals(tableName)){
                    // 不增加租户信息
                    return true;
                }
                return false;
            }
        });

        sqlParsers.add(tenantSqlParser);

        paginationInterceptor.setSqlParserList(sqlParsers);


        /
            【特定sql 过滤】，可用注解替换
            @SqlParser(filter = true) 为true表示，不在此方法上增加租户信息
         /
        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
            @Override
            public boolean doFilter(MetaObject metaObject) {

                MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);

                if ("cn.mesmile.mybatisplusdemo.mapper.EmployeeMapper.selectAll"
                        .equals(ms.getId())) {
                    // 同时这个方法对 动态表明解析也会产生作用，也会过滤掉动态表名，只显示原来的表名
                    // 不增加租户信息
                    return true;
                }

                return false;
            }

        });

         */

        return paginationInterceptor;
    }

    /**
     *  乐观锁插件
     * @return
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     *  防止全表更新或删除
     * @return
     */
    @Bean
    public BlockAttackInnerInterceptor blockAttackInnerInterceptor(){
        return new BlockAttackInnerInterceptor();
    }

    /**
     * 性能分析插件,SQL 执行性能分析，开发环境使用，线上不推荐
     * @return
     */
//    @Bean
//    @Profile({"dev","test"})// 设置 dev test 环境开启
//    public PerformanceInterceptor performanceInterceptor() {
//        return new PerformanceInterceptor();
//    }
}
